package top.goldenyear.porpoise.dev.code.service;

import cn.hutool.v7.core.collection.CollUtil;
import cn.hutool.v7.core.text.StrUtil;
import cn.hutool.v7.core.util.ObjUtil;
import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.solon.annotation.Db;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import top.goldenyear.porpoise.common.core.exception.ErrorCode;
import top.goldenyear.porpoise.common.core.exception.ServiceException;
import top.goldenyear.porpoise.common.core.model.PlainOption;
import top.goldenyear.porpoise.dev.code.model.CodeDb;
import top.goldenyear.porpoise.dev.code.model.proxy.CodeDbProxy;
import top.goldenyear.porpoise.framework.web.core.annotation.Deform;
import top.goldenyear.porpoise.framework.web.core.generator.MetaBuilder;
import top.goldenyear.porpoise.framework.web.core.generator.config.GlobalConfig;
import top.goldenyear.porpoise.framework.web.core.generator.config.StrategyConfig;
import top.goldenyear.porpoise.framework.web.core.generator.config.TableConfig;
import top.goldenyear.porpoise.framework.web.core.generator.dialect.impl.JdbcTypeMapping;
import top.goldenyear.porpoise.framework.web.core.generator.model.TableMeta;
import top.goldenyear.porpoise.framework.web.core.model.PageResult;
import top.goldenyear.porpoise.framework.web.core.model.query.QPage;
import top.goldenyear.porpoise.framework.web.core.service.BaseService;

/**
 * 数据源 Service 服务层
 *
 * @author airhead
 * @since 2025-02-04
 */
@Component
@Slf4j
public class CodeDbService extends BaseService<CodeDb, CodeDbProxy> {
  @Db private EasyEntityQuery easyEntityQuery;
  @Inject private CodeDbService codeDbService;

  public CodeDbService() {
    super(CodeDb.class, CodeDbProxy.class);
  }

  public Boolean createCodeDb(CodeDb codeDb) {
    return save(codeDb);
  }

  public Boolean updateCodeDb(CodeDb codeDb) {
    return updateById(codeDb);
  }

  public CodeDb getCodeDb(Long id) {
    return getById(id);
  }

  public Boolean deleteCodeDb(Long id) {
    if (getById(id) == null) {
      throw new ServiceException(ErrorCode.builder().msg("记录不存在").build());
    }

    return deleteById(id);
  }

  public Boolean batchDelCodeDb(List<Long> ids) {
    for (Long id : ids) {
      if (getById(id) == null) {
        throw new ServiceException(ErrorCode.builder().msg("记录不存在").build());
      }
    }

    return deleteByIds(ids);
  }

  public List<CodeDb> listCodeDb(CodeDb codeDb) {
    return list(codeDb);
  }

  @Deform(keep = {"id", "name"})
  public List<CodeDb> simpleListCodeDb(CodeDb codeDb) {
    return list(codeDb);
  }

  public PageResult<CodeDb> paginateCodeDb(QPage qPage, CodeDb codeDb) {
    return paginate(qPage, codeDb);
  }

  public List<PlainOption> optionsCodeDb(CodeDb codeDb) {
    return listAs(codeDb, PlainOption.class);
  }

  public List<TableMeta> getTableList(Integer dbId, String nameLike, String commentLike) {
    List<TableMeta> tableMetas = getTableList0(dbId, null);
    return tableMetas.stream()
        .filter(
            tableInfo ->
                (StrUtil.isEmpty(nameLike) || tableInfo.getName().contains(nameLike))
                    && (StrUtil.isEmpty(commentLike)
                        || tableInfo.getComment().contains(commentLike)))
        .collect(Collectors.toList());
  }

  public TableMeta getTable(Integer dbId, String name) {
    return CollUtil.getFirst(getTableList0(dbId, name));
  }

  public DataSource getDataSourceById(Integer dbId) {
    CodeDb config = codeDbService.getById(dbId);
    return getHikariDataSource(config);
  }

  @Override
  protected EasyEntityQuery easyEntityQuery() {
    return easyEntityQuery;
  }

  private List<TableMeta> getTableList0(Integer dbId, String name) {
    if (ObjUtil.isNull(dbId)) {
      return new ArrayList<>();
    }

    // 获得数据源配置
    CodeDb config = codeDbService.getById(dbId);

    HikariDataSource dataSource = getHikariDataSource(config);
    GlobalConfig globalConfig = GlobalConfig.of();
    StrategyConfig strategyConfig = globalConfig.getStrategyConfig();
    strategyConfig.setOnlyGenAssignTable(true);
    if (StrUtil.isNotEmpty(name)) {
      strategyConfig.addTableConfig(TableConfig.of().setTableName(name));
    } else {
      // 移除工作流和定时任务前缀的表名
      // 移除 ORACLE 相关的系统表
      // 表里不能有 $，一般有都是系统的表
      strategyConfig.setBlackList(
          "ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+",
          "IMPDP_[\\S\\s]+|ALL_[\\S\\s]+|HS_[\\S\\\\s]+",
          "[\\S\\s]+\\$[\\S\\s]+|[\\S\\s]+\\$");
    }

    JdbcTypeMapping.registerMapping(Timestamp.class, Date.class);
    MetaBuilder metaBuilder = new MetaBuilder(dataSource, globalConfig);
    return metaBuilder.buildTables();
  }

  private HikariDataSource getHikariDataSource(CodeDb config) {
    HikariConfig hikariConfig = new HikariConfig();
    hikariConfig.setJdbcUrl(config.getUrl());
    hikariConfig.setUsername(config.getUsername());
    hikariConfig.setPassword(config.getPassword());
    return new HikariDataSource(hikariConfig);
  }
}
